package cn.redsoft.wechatapi.common.servlet;

import java.io.IOException;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.dom4j.DocumentException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import cn.redsoft.wechatapi.common.Consts;
import cn.redsoft.wechatapi.common.exception.NoHandlerMatchedException;
import cn.redsoft.wechatapi.common.util.SignatureUtil;
import cn.redsoft.wechatapi.common.util.XMLFormater;
import cn.redsoft.wechatapi.common.util.XMLParser;
import cn.redsoft.wechatapi.handler.RequestMsgHandlerInvoker;
import cn.redsoft.wechatapi.msg.req.RequestMsg;
import cn.redsoft.wechatapi.msg.resp.passivity.PassivityResponseMsg;

public class DefaultWeChatServlet extends HttpServlet {
	private static final long serialVersionUID = 1L;
	private RequestMsgHandlerInvoker invoker = new RequestMsgHandlerInvoker();

	protected Logger log = LoggerFactory.getLogger(DefaultWeChatServlet.class);

	protected void doGet(HttpServletRequest request,
			HttpServletResponse response) throws ServletException, IOException {
		log.debug("<== WeChat 调试信息 (将logger:cn.redsoft.wechat 级别设置为 DEBUG 级别之上以关闭调试信息): ====================>");
		log.debug("<==start====================>");
		String signature = request.getParameter("signature");
		String timestamp = request.getParameter("timestamp");
		String nonce = request.getParameter("nonce");
		String echostr = request.getParameter("echostr");
		OutputStream outputStream = response.getOutputStream();
		try {
			if (echostr != null && echostr.length() > 0) {
				this.signatureValidation(signature, timestamp, nonce, echostr,
						outputStream);
			} else {
				this.parseAndReplyMsg(request, outputStream);
			}
		} catch (DocumentException e) {
			e.printStackTrace();
		} catch (NoHandlerMatchedException e) {
			e.printStackTrace();
			outputStream.write("".getBytes());
		} catch (InstantiationException e) {
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			e.printStackTrace();
		}

		outputStream.flush();
		outputStream.close();

		log.debug("<==end====================>");
		log.debug("\n\n");
	}

	protected void doPost(HttpServletRequest request,
			HttpServletResponse response) throws ServletException, IOException {
		this.doGet(request, response);
	}

	protected void parseAndReplyMsg(HttpServletRequest request,
			OutputStream outputStream) throws IOException, DocumentException,
			InstantiationException, IllegalAccessException,
			UnsupportedEncodingException {
		XMLParser parser = new XMLParser();
		XMLFormater formater = new XMLFormater();
		String string = parser.getXMLStringFromRequest(request);
		RequestMsg msg = parser.parseMsgFromXMLString(string);
		String replyXmlString = "";
		PassivityResponseMsg responseMsg = invoker.invokeHandler(msg);
		if (responseMsg != null) {
			replyXmlString = formater.format(responseMsg, true);
		}
		outputStream.write(replyXmlString.getBytes(Consts.CHARACTER_ENCODING));
		if (replyXmlString.equals("")) {
			log.debug("--------------------------------------");
			log.debug("==> Handler返回null,不回复消息 .");
		} else {
			log.debug("--------------------------------------");
			log.debug("==> 回复消息 :");
			log.debug("\t==> 1. ResponseMsgType : 【=> {}】 .", responseMsg
					.getMsgType().getValue());
			log.debug("\t==> 2. MsgBean : {} .", responseMsg.toString());
			log.debug("\t==> 3. MsgBean-->xml :\n{}", replyXmlString);
			log.debug("==> 回复消息完毕.");
		}
		log.debug("=================================>");
	}

	/**
	 * 签名认证
	 * 
	 * @param signature
	 * @param timestamp
	 * @param nonce
	 * @param echostr
	 * @param outputStream
	 * @throws IOException
	 * @throws UnsupportedEncodingException
	 */
	protected void signatureValidation(String signature, String timestamp,
			String nonce, String echostr, OutputStream outputStream)
			throws IOException, UnsupportedEncodingException {
		log.debug("\tsignature validation start");
		if (SignatureUtil.checkSignature(signature, timestamp, nonce)) {
			outputStream.write(echostr.getBytes(Consts.CHARACTER_ENCODING));
			log.debug("\t\tsignature validation ok");
		} else {
			log.debug("\t\tsignature validation error");
		}
		log.debug("\tsignature validation end");
	}

}
